import requests
from flask import jsonify, request

from model.cluster import Cluster, ClusterRelatedInstance
from model.prom_sites import PromSites

from blues.cluster import bp
from config import K8s_API_PREFIX, UA

from public.time_utils import get_range_ts, seconds_to_days

import urllib3
from kubernetes import client
from public.time_utils import getNowTS



# 获取k8s客户端
def get_client_by_token(host, token):
    # 解决Python3 控制台输出InsecureRequestWarning的问题
    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
    # Configs can be set in Configuration class directly or using helper utility
    cfg = client.Configuration()
    cfg.host = host
    cfg.verify_ssl = False
    cfg.api_key = {"authorization": "Bearer " + token}
    client.Configuration.set_default(cfg)
    return client


##### yaml相关接口
@bp.route('/api/cluster/<cluster_id>/createfromyaml', methods=['POST'])
def create_from_yaml(cluster_id):

    c = Cluster()
    cluster = c.find_by_id(cluster_id)
    # 调用k8s apiserver

    data = request.json
    # print(data["data"])

    yaml_file = './upload/yaml_' + getNowTS() + '.yaml'
    with open(yaml_file, 'w') as f:
        f.write(data["data"])

    client = get_client_by_token(cluster['apiserver'], cluster['token'])
    k8s_client = client.ApiClient()
    try:
        create_from_yaml(k8s_client, yaml_file, verbose=True)
        result = "创建成功"
    except Exception as e:
        print("K8s SDK 报错：")
        print(e)
        result = str(e)
    return jsonify({"code": 200, "message": result})


@bp.route('/api/cluster/<cluster_id>/<namespace>/<type>/<name>/yaml')
def get_resource_yaml(cluster_id, namespace, type='', name=''):
    from public.utils import json2yaml
    c = Cluster()
    cluster = c.find_by_id(cluster_id)
    # 调用k8s apiserver
    url = cluster['apiserver'] + K8s_API_PREFIX[type] + "/namespaces/" + namespace + "/" + type + "/" + name
    if namespace == '_all':
        url = cluster['apiserver'] + K8s_API_PREFIX[type] + "/" + type + "/" + name
    headers = {"Authorization": "Bearer " + cluster['token'], "User-Agent": UA}
    response = requests.get(url=url, headers=headers, verify=False)
    # 将json格式的k8s资源声明，转化为YAML格式返回
    return jsonify({"code": 200, "yaml": json2yaml(response.text)})


@bp.route('/api/v1/cluster/<cluster_id>/<namespace>/<type>/<name>/replace', methods=['POST'])
def replace_yaml(cluster_id, namespace, type, name):
    data = request.json
    # print(json.dumps(data))
    print(data["data"])
    c = Cluster()
    cluster = c.find_by_id(cluster_id)
    url = cluster['apiserver'] + K8s_API_PREFIX[type] + "/namespaces/" + namespace + "/" + type + "/" + name
    headers = {"Content-Type": "application/yaml", "Authorization": "Bearer " + cluster['token'], "User-Agent": UA}
    response = requests.put(url=url, headers=headers, data=data["data"].encode('utf-8'), verify=False)
    print(response.text)
    res = {'code': response.status_code, 'msg': response.json()}
    return jsonify(res)




# 获取K8s集群列表
@bp.route('/api/cluster_list/')
def get_cluster_list():
    c = Cluster()
    list = c.find_all()
    return jsonify(list)


# 添加K8s集群
@bp.route('/api/add_cluster/', methods=['POST'])
def add_cluster():
    data = request.json
    print(data)
    c = Cluster()
    res = c.add_cluster(data['name'], data['apiserver'], data['token'], data['prom'])
    if res == 'ok':
        return jsonify({"code": 200, "message": res})
    else:
        return jsonify({"code": 500, "message": res})



@bp.route('/api/v1/cluster/<cluster_id>')
def get_cluster(cluster_id):
    c = Cluster()
    dict = c.find_by_id(cluster_id)
    return jsonify(dict)


def get_cluster_dict():
    c = Cluster()
    clusters = c.find_all()
    dict = {}
    for i in clusters:
        dict[i['id']] = i['name']
    return dict


@bp.route('/api/v1/cluster/<id>/namespaces')
def get_namesapce(id):
    c = Cluster()
    cluster = c.find_by_id(id)
    # 调用k8s apiserver
    url = cluster['apiserver'] + "/api/v1/namespaces"
    headers = {"Authorization": "Bearer " + cluster['token'], "User-Agent": UA}
    response = requests.get(url=url, headers=headers, verify=False)
    # print(response.text)
    try:
        return response.json()
    except Exception as e:
        print(e)
        return response.text


@bp.route('/api/v1/cluster/<cluster_id>/nodes')
def nodes(cluster_id):
    c = Cluster()
    cluster = c.find_by_id(cluster_id)
    # 调用k8s apiserver
    url = cluster['apiserver'] + "/api/v1/nodes"
    headers = {"Authorization": "Bearer " + cluster['token'], "User-Agent": UA}
    response = requests.get(url=url, headers=headers, verify=False)
    # print(response.text)
    try:
        return response.json()
    except Exception as e:
        print(e)
        return ''


@bp.route('/api/v2/cluster/<cluster_id>/nodes')
def nodes_v2(cluster_id):
    c = Cluster()
    cluster = c.find_by_id(cluster_id)
    # 调用k8s apiserver，获取node基本信息
    url = cluster['apiserver'] + "/api/v1/nodes"
    headers = {"Authorization": "Bearer " + cluster['token'], "User-Agent": UA}
    response = requests.get(url=url, headers=headers, verify=False)
    # print(response.text)
    # print(response.json())
    try:
        res = response.json()
    except Exception as e:
        print(e)
        return ''
    dic = {}
    for i in res['items']:
        name = i['metadata']['name']
        role = 'Worker'
        if 'node-role.kubernetes.io/master' in i['metadata']['labels']:
            role = 'Master'
        storage = i['status']['capacity']['ephemeral-storage']
        storage = str(storage).rstrip('Ki')
        storage = round(int(storage) / 1024 / 1024)
        memory = i['status']['capacity']['memory']
        memory = str(memory).rstrip('Ki')
        memory = round(int(memory) / 1024 / 1024)
        conditions = ''
        for j in i['status']['conditions']:
            if j['status'] == 'True':
                conditions += j['type'] + ','
            elif j['status'] == 'Unknown':
                conditions += j['message']
        conditions = conditions.rstrip(',')

        dic[name] = {}
        dic[name]['name'] = i['metadata']['name']
        dic[name]['role'] = role
        dic[name]['specs'] = str(i['status']['capacity']['cpu']) + 'C|' + str(memory) + 'G|' + str(storage) + 'G'
        dic[name]['pods'] = i['status']['capacity']['pods']
        dic[name]['conditions'] = conditions
        dic[name]['cpu_use'] = ''
        dic[name]['mem_use'] = ''
        dic[name]['disk_use'] = ''
    if cluster['prom']:
        # 调用prom接口获取node监控信息
        try:
            url_prom = cluster['prom'] + "/api/v1/query"
            params = {'query': "100-(avg by(instance) (rate(node_cpu_seconds_total{mode='idle'}[2m])) * 100)"}
            response = requests.get(url=url_prom, headers=headers, verify=False, params=params)
            res_cpu = response.json()
            # print(response.text)
            params = {'query': "(1-node_memory_MemAvailable_bytes/node_memory_MemTotal_bytes)*100"}
            response = requests.get(url=url_prom, headers=headers, verify=False, params=params)
            res_mem = response.json()
            # print(response.text)
            params = {
                'query': "max((node_filesystem_size_bytes{fstype=~'ext.?|xfs'}-node_filesystem_free_bytes{fstype=~'ext.?|xfs'})/(node_filesystem_size_bytes{fstype=~'ext.?|xfs'})*100)by(instance)"
            }
            response = requests.get(url=url_prom, headers=headers, verify=False, params=params)
            res_disk = response.json()
            # print(response.text)
            for i in res_cpu['data']['result']:
                value = round(float(i['value'][1]))
                if i['metric']['instance'] in dic:
                    dic[i['metric']['instance']]['cpu_use'] = str(value) + '%'
            for i in res_mem['data']['result']:
                value = round(float(i['value'][1]))
                if i['metric']['instance'] in dic:
                    dic[i['metric']['instance']]['mem_use'] = str(value) + '%'
            for i in res_disk['data']['result']:
                value = round(float(i['value'][1]))
                if i['metric']['instance'] in dic:
                    dic[i['metric']['instance']]['disk_use'] = str(value) + '%'
        except Exception as e:
            print(e)

    li = []
    for _, v in dic.items():
        li.append(v)

    try:
        return jsonify({"code": 200, "data": li})
    except Exception as e:
        print(e)
        return ''


@bp.route('/api/v1/cluster/<cluster_id>/prom/healthy')
def clusterPromHealthy(cluster_id):
    if not cluster_id or cluster_id == 'null':
        return 'bad cluster id'
    c = Cluster()
    cluster = c.find_by_id(cluster_id)
    # 调用prom api
    if not cluster['prom']:
        msg = 'cluster {} have no prom'.format(cluster_id)
        print(msg)
        return msg
    url = cluster['prom'] + "/-/healthy"
    headers = {"User-Agent": UA}
    response = requests.get(url=url, headers=headers, verify=False)
    print(response.text)
    if response.text.strip() == 'Prometheus is Healthy.':
        return 'ok'
    else:
        return 'not ok'


@bp.route('/api/v1/cluster/<cluster_id>/prom/query')
def clusterPromQuery(cluster_id):
    if not cluster_id or cluster_id == 'null':
        return ''
    c = Cluster()
    cluster = c.find_by_id(cluster_id)
    params = {'query': request.args.get('query')}
    # 调用prom api
    if not cluster['prom']:
        print('cluster {} have no prom'.format(cluster_id))
        return ''
    url = cluster['prom'] + "/api/v1/query"
    headers = {"User-Agent": UA}
    response = requests.get(url=url, headers=headers, verify=False, params=params)
    # print(response.text)
    try:
        return response.json()
    except Exception as e:
        print(e)
        return ''


def clusterPromQuery(cluster_id, query):
    c = Cluster()
    cluster = c.find_by_id(cluster_id)
    params = {'query': query}
    # 调用prom api
    if not cluster['prom']:
        print('cluster {} have no prom'.format(cluster_id))
        return ''
    url = cluster['prom'] + "/api/v1/query"
    headers = {"Authorization": "Bearer " + cluster['token'], "User-Agent": UA}
    try:
        response = requests.get(url=url, headers=headers, verify=False, params=params)
        # print(response.text)
        return response.json()
    except Exception as e:
        print("prom请求失败", str(e))
        return ''


@bp.route('/api/v1/cluster/<cluster_id>/prom/query_range')
def clusterPromQueryRange(cluster_id):
    if not cluster_id or cluster_id == 'null':
        return ''
    c = Cluster()
    cluster = c.find_by_id(cluster_id)
    time_range = request.args.get('time_range')
    start, end = get_range_ts(time_range)
    # print(start,end)
    step_dict = {
        "hour": 60,
        "day": 60 * 10,
        "week": 60 * 60
    }
    params = {
        'query': request.args.get('query'),
        # 'query': "1-(avg by(instance) (rate(node_cpu_seconds_total{mode='idle'}[2m])))",
        'start': start,
        'end': end,
        'step': step_dict[time_range],
    }
    # 调用prom api
    if not cluster['prom']:
        print('cluster {} have no prom'.format(cluster_id))
        return ''
    url = cluster['prom'] + "/api/v1/query_range"
    headers = {"Authorization": "Bearer " + cluster['token'], "User-Agent": UA}
    response = requests.get(url=url, headers=headers, verify=False, params=params)
    # print(response.text)
    try:
        return response.json()
    except Exception as e:
        print(e)
        return ''


@bp.route('/api/v1/cluster/<cluster_id>/prom/mysql_mon_info')
def clusterPromMysqlMonInfo(cluster_id):
    if not cluster_id or cluster_id == 'null':
        return 'bad cluster id'
    c = Cluster()
    cluster = c.find_by_id(cluster_id)
    params = {'query': 'mysql_up'}
    # 调用prom api
    if not cluster['prom']:
        msg = 'cluster {} have no prom'.format(cluster_id)
        print(msg)
        return msg
    url = cluster['prom'] + "/api/v1/query"
    headers = {"User-Agent": UA}
    response = requests.get(url=url, headers=headers, verify=False, params=params)
    print(response.text)
    data = response.json()

    li = []
    for i in data['data']['result']:
        instance = i['metric']['instance']
        # uptime
        response = requests.get(url=url, headers=headers, params={'query': 'mysql_global_status_uptime'})
        uptime = response.json()
        print(uptime)
        uptime = uptime['data']['result'][0]['value'][1]
        uptime = seconds_to_days(int(uptime))
        # qps
        response = requests.get(url=url, headers=headers,
                                params={'query': 'rate(mysql_global_status_queries{instance="' + instance + '"}[5m])'})
        qps = response.json()['data']['result'][0]['value'][1]
        # current conn
        response = requests.get(url=url, headers=headers, params={
            'query': 'max_over_time(mysql_global_status_threads_connected{instance="' + instance + '"}[5m])'})
        cur_conn = response.json()['data']['result'][0]['value'][1]
        # max conn
        response = requests.get(url=url, headers=headers, params={
            'query': 'mysql_global_variables_max_connections{instance="' + instance + '"}'})
        max_conn = response.json()['data']['result'][0]['value'][1]

        info = {"instance": instance, "uptime": uptime, "qps": qps, "cur_conn": cur_conn, "max_conn": max_conn}
        # slow
        response = requests.get(url=url, headers=headers, params={
            'query': 'rate(mysql_global_status_slow_queries{instance="' + instance + '"}[5m])'})
        slow = response.json()['data']['result'][0]['value'][1]
        # net_in
        response = requests.get(url=url, headers=headers, params={
            'query': 'rate(mysql_global_status_bytes_received{instance="' + instance + '"}[5m])'})
        net_in = response.json()['data']['result'][0]['value'][1]
        # net_out
        response = requests.get(url=url, headers=headers, params={
            'query': 'rate(mysql_global_status_bytes_sent{instance="' + instance + '"}[5m])'})
        net_out = response.json()['data']['result'][0]['value'][1]

        info = {"instance": instance, "uptime": uptime, "qps": round(float(qps), 1), "conn": cur_conn + "/" + max_conn,
                "slow": round(float(slow), 2), "net_in": int(float(net_in)), "net_out": int(float(net_out))}

        li.append(info)

    return jsonify({"code": 200, "data": li})


@bp.route('/api/v1/cluster/add_instance', methods=['POST'])
def addClusterRelatedInstance():
    data = request.json
    print(data)
    try:
        ps = PromSites()
        p = ps.find_by_id(data['prom_id'])
        c = ClusterRelatedInstance()
        c.add_instance(
            cluster_id=data['cluster_id'],
            prom_id=data['prom_id'],
            prom_url=p['url'],
            instance=data['instance']
        )
        return jsonify({"code": 200, "message": "集群关联系统成功!"})
    except Exception as e:
        print(e)
        return jsonify({"code": 500, "message": str(e)})


@bp.route('/api/v1/cluster/get_instance', methods=['GET'])
def getClusterRelatedInstance():
    cluster_id = request.args.get('cluster_id')
    try:
        c = ClusterRelatedInstance()
        cri_li = c.find_by_cluster_id(cluster_id)
        return jsonify({"code": 200, "data": cri_li})
    except Exception as e:
        print(e)
        return jsonify({"code": 500, "message": str(e)})


if __name__ == '__main__':
    url_prom = 'http://119.45.8.107:30002/api/v1/query'
    params = {'query': "(1-node_memory_MemAvailable_bytes/node_memory_MemTotal_bytes)*100"}
    response = requests.get(url=url_prom, verify=False, params=params)
    res_disk = response.json()
    print(response.text)
